Back Moon
by Pete TownZeke
Summary: When a new season of Total Drama goes horrible wrong, and now the contestants are stranded on the dark side of the moon. With only a limited supply of oxygen to go around, A small band of interns decide to risk their lives to save the remaining contestants. This is their story. Courtney/Alejandro, Harold/Cody, Sierra/Duncan, OC/OC, OC/Chef, Mal/Dawn, Heather/Gwen, Noah/Chris.


p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"Observe:span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);span style="max-height: 999999px;"Observe:/spanstruct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);span style="max-height: 999999px;"Observe:/spanstruct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"span style="max-height: 999999px;"a style="color: #0f37a0;" href=" . ?sub=1ppage=14"Replya /span14h ago . Edited 14h ago #402span style="max-height: 999999px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks; atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) { free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); } EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups;/span/p  
>p style="max-height: 999999px; font-family: Verdana, Verdana, Arial; font-size: 14px;"struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize NGROUPS_PER_BLOCK - 1)  NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info-ngroups = gidsetsize; group_info-nblocks = nblocks;atomic_set(group_info-usage, 1); if (gidsetsize = NGROUPS_SMALL) group_info-blocks[0] = group_info-small_block; else { for (i = 0; i nblocks; i) { gid_t *b; b = (void *)_get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info-blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (-i = 0) {free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); return NULL; } EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { if (group_info-blocks[0] != group_info-small_block) { int i; for (i = 0; i group_info-nblocks; i) free_page((unsigned long)group_info-blocks[i]); } kfree(group_info); }EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */ static int groups_to_user(gid_t _user *grouplist, const struct group_info *group_info) { int i;unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist, group_info-blocks[i], len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* fill a group_info from a user-space array - it must be allocated already */ static int groups_from_user(struct group_info *group_info, gid_t _user *grouplist) { int i; unsigned int count = group_info-ngroups; for (i = 0; i group_info-nblocks; i) { unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); unsigned int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info-blocks[i], grouplist, len)) return -EFAULT; grouplist = NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* a simple Shell sort */ static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info-ngroups; for (stride = 1; stride gidsetsize; stride = 3 * stride 1) ; /* nothing */stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base max; base) { int left = base; int right = left stride; gid_t tmp = GROUP_AT(group_info, right); while (left = 0 GROUP_AT(group_info, left) tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp;} stride /= 3; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info-ngroups; while (left right) { unsigned int mid = (leftright)/2; if (grp GROUP_AT(group_info, mid)) left = mid 1; else if (grp GROUP_AT(group_info, mid)) right = mid;else return 1; } return 0; } /** * set_groups - Change a group subscription in a set of credentials * new: The newly prepared set of credentials to alter * group_info: The group list to install * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int set_groups(struct cred *new, struct group_info *group_info) {put_group_info(new-group_info); groups_sort(group_info); get_group_info(group_info); new-group_info = group_info; return 0; } EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */ int set_current_groups(struct group_info *group_info) { struct cred *new; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret 0) { abort_creds(new); return ret; } return commit_creds(new); } EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t _user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred-group_info-ngroups; if (gidsetsize) { if (i gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred-group_info)) { i = -EFAULT; goto out; } } out: return i; } /* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t _user *, grouplist) { struct group_info *group_info; int retval; if (!nsown_capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ int in_group_p(gid_t grp) {const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-fsgid) retval = groups_search(cred-group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred-egid) retval = groups_search(cred-group_info, grp);/p 


End file.
